package com.arpa.ntocc.common.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.json.JSONUtil;
import com.arpa.ntocc.common.common.Page;
import com.arpa.ntocc.common.common.cache.*;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.RedisUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.ntocc.common.common.util.ValidateUtil;
import com.arpa.ntocc.common.domain.dto.*;
import com.arpa.ntocc.common.domain.entity.Party;
import com.arpa.ntocc.common.domain.entity.PartyRole;
import com.arpa.ntocc.common.domain.entity.Role;
import com.arpa.ntocc.common.domain.entity.UserLogin;
import com.arpa.ntocc.common.domain.enums.EmploymentTypeEnum;
import com.arpa.ntocc.common.domain.enums.PartyTypeEnum;
import com.arpa.ntocc.common.domain.vo.PartyBalanceStatisticsVo;
import com.arpa.ntocc.common.domain.vo.PartyVO;
import com.arpa.ntocc.common.mapper.*;
import com.arpa.ntocc.common.service.IFileInfoService;
import com.arpa.ntocc.common.service.IPartyGroupService;
import com.arpa.ntocc.common.service.IPartyResourceService;
import com.arpa.ntocc.common.service.IPartyService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author liuyj
 * @since 2019-11-25
 */
@Service
@Log4j2
@Validated
public class PartyServiceImpl extends ServiceImpl<PartyMapper, Party> implements IPartyService {


    private static final String VALIDATE_PHONE = "手机号格式不合法";
    private static final String DEFAULT_PD = "abcd1234";
    private final static String INVALID_PASSWORD_FORMAT_ALPHANUMERIC_COMBINATION_MORE_THAN_EIGHT_DIGITS = "密码格式不合法，数字字母组合 8位及以上";

    @Resource
    ShipmentMapper shipmentMapper;
    @Autowired
    IFileInfoService fileInfoService;
    @Resource
    UserLoginMapper userLoginMapper;
    @Autowired
    @Lazy
    PartyCache partyCache;
    @Resource
    RoleMapper roleMapper;
    @Resource
    PartyRoleMapper partyRoleMapper;
    @Autowired
    RoleCache roleCache;
    @Autowired
    PartyGroupCache partyGroupCache;
    @Autowired
    @Lazy
    DepartmentCache departmentCache;
    @Autowired
    private IPartyResourceService partyResourceService;
    @Autowired
    private IPartyGroupService partyGroupService;

    /**
     * 通过code查询用户
     *
     * @param code
     * @return
     */
    @Override
    public Party getByCode(String code) {
        return baseMapper.selectOne(new QueryWrapper<Party>().lambda().eq(Party::getCode, code));
    }

    @Override
    public boolean createParty(Party entity) {
        return super.save(entity);
    }







    /**
     * 保存用户角色信息
     *
     * @param entity
     */
    private void saveOrUpdateRoleInfo(PartyDTO entity) {
        if (entity != null) {
            String partyCode = entity.getCode();
            List<String> roleCodeList = entity.getRoleCodeList();
            //删除老的用户角色关系
            partyRoleMapper.delete(new QueryWrapper<PartyRole>().lambda().eq(PartyRole::getPartyCode, partyCode));
            //创建新用户角色关系
            if (!CollectionUtils.isEmpty(roleCodeList)) {
                roleCodeList.forEach(roleCode -> {
                    PartyRole partyRole = new PartyRole();
                    partyRole.setCode(IdUtil.simpleUUID());
                    partyRole.setPartyCode(partyCode);
                    partyRole.setRoleCode(roleCode);
                    partyRole.setCreatedBy(UserUtil.getCode());
                    partyRoleMapper.insert(partyRole);
                });
            }
        }
    }

    /**
     * 保存用户角色
     *
     * @param partyCode
     */
    private void savePartyRole(String partyCode, PartyTypeEnum partyTypeEnum) {
        log.info("创建用户【{}】信息，保存用户类型【{}】。", partyCode, partyTypeEnum);
        if (partyTypeEnum != null && StringUtils.isNotEmpty(partyCode)) {
            PartyRole partyRole = new PartyRole();
            Role role = roleMapper.selectOne(new QueryWrapper<Role>().lambda().eq(Role::getRole, partyTypeEnum.getValue()));
            if (role != null) {
                partyRole.setCode(IdUtil.simpleUUID());
                partyRole.setPartyCode(partyCode);
                partyRole.setRoleCode(role.getCode());
                partyRole.setCreatedBy(partyCode);
                partyRoleMapper.insert(partyRole);
            }
        }
    }





    /**
     * 查询列表
     *
     * @param partyDTO
     * @return
     */
    @Override
    public List<PartyVO> queryList(PartyDTO partyDTO) {
        //排序字段名需要驼峰转数据库下划线类型字段名
        if (StringUtils.isNotEmpty(partyDTO.getSortField())) {
            partyDTO.setSortField(CommonUtil.camel2Underline(partyDTO.getSortField()));
        }
        List<PartyVO> partyVOList = baseMapper.queryList(partyDTO);
        //查询角色信息（用户和角色，一对多关系）
        if (partyDTO.getIsQueryRole() != null && partyDTO.getIsQueryRole() == 1) {
            queryRoleInfo(partyVOList);
        }
        return partyVOList.stream().peek(info -> {
            if (StrUtil.isNotEmpty(info.getEnrollmentDate())) {
                info.setEnrollmentDate(info.getEnrollmentDate().substring(0, 10));
            }
            if (StrUtil.isNotBlank(info.getEmploymentType())) {
                info.setEmploymentTypeText(EmploymentTypeEnum.translate(info.getEmploymentType()));
            }

        }).collect(Collectors.toList());
    }

    /**
     * 查询用户列表的角色信息
     *
     * @param partyVOList
     */
    private void queryRoleInfo(List<PartyVO> partyVOList) {
        if (!CollectionUtils.isEmpty(partyVOList)) {
            List<String> partyCodes = partyVOList.stream().map(PartyVO::getCode).collect(Collectors.toList());
            //查询用户角色表
            List<PartyRole> partyRoleList = partyRoleMapper.selectList(new QueryWrapper<PartyRole>().lambda().in(PartyRole::getPartyCode, partyCodes));
            //查询角色信息
            if (!CollectionUtils.isEmpty(partyRoleList)) {
                for (PartyVO partyVO : partyVOList) {
                    List<RoleCacheDO> roleList = partyRoleList.stream()
                            .filter(partyRole -> partyRole.getPartyCode().equals(partyVO.getCode()))
                            .map(partyRole -> {
                                RoleCacheDO role = roleCache.get(partyRole.getRoleCode());
                                return role;
                            }).collect(Collectors.toList());
                    partyVO.setRoleList(roleList);
                }
            }
        }
    }

    /**
     * 查询合计,包含总数
     *
     * @param partyDTO
     * @return
     */
    @Override
    public PartyVO queryListSum(PartyDTO partyDTO) {
        PartyVO partyVO = baseMapper.queryListSum(partyDTO);
        return partyVO;
    }





    /**
     * 校验验证码（后门验证码802208，方便测试）
     *
     * @param phone
     * @param verifyCode
     */
    private void validateVerifyCode(String phone, String verifyCode) {
        String key = "verifyCode_" + phone;
        String redisValue = RedisUtil.get(key);
        if (StringUtils.isNotEmpty(redisValue)) {
            String redisVerifyCode = redisValue.split("\\|")[0];
            if (!verifyCode.equals(redisVerifyCode)) {
                throw new ServiceException("验证码不正确");
            }
        } else {
            throw new ServiceException("验证码不正确");
        }
    }




    /**
     * 根据明文密码和salt获取加密后密码
     *
     * @param pwd
     * @param salt
     * @return
     */
    public String getPasswd(String pwd, String salt) {
        //根据密码，和salt 生成数据库的加密密码
        String password = SmUtil.sm3(pwd + salt);
        return password;
    }



    /**
     * 查询用户信息，包含角色
     *
     * @param code
     * @return
     */
    @Override
    public PartyVO queryPartyInfo(String code) {
        Party party = baseMapper.selectOne(Wrappers.lambdaQuery(Party.class).eq(Party::getCode, code));
        PartyVO partyVO = new PartyVO();
        BeanUtil.copyProperties(party, partyVO);
        UserLogin userLogin = userLoginMapper.selectOne(Wrappers.lambdaQuery(UserLogin.class).eq(UserLogin::getUserLoginId, code));
        if(userLogin!=null){
          String warehouseAuthorization= userLogin.getWarehouseAuthorization();
          if(StrUtil.isNotBlank(warehouseAuthorization)){
              List<WarehouseAuthorizationJsonBean> warehouseAuthorizationJsonBeans = JSONUtil.toList(warehouseAuthorization,WarehouseAuthorizationJsonBean.class);
              partyVO.setWarehouseAuthorization(warehouseAuthorizationJsonBeans);
          }
          String shipmentAuthorization= userLogin.getShipmentAuthorization();
          if(StrUtil.isNotBlank(shipmentAuthorization)){
              List<ShipmentAuthorizationJsonBean> shipmentAuthorizationJsonBeans = JSONUtil.toList(shipmentAuthorization,ShipmentAuthorizationJsonBean.class);
              partyVO.setShipmentAuthorization(shipmentAuthorizationJsonBeans);
          }
        }


    /*    //查询用户角色表
        List<PartyRole> partyRoleList = partyRoleMapper.selectList(new QueryWrapper<PartyRole>().lambda().eq(PartyRole::getPartyCode, code));
        //set用户角色信息
        if (!CollectionUtils.isEmpty(partyRoleList)) {
            List<String> roleCodeList = partyRoleList.stream()
                    .filter(partyRole -> partyRole.getPartyCode().equals(partyVO.getCode()))
                    .map(PartyRole::getRoleCode).collect(Collectors.toList());
            partyVO.setRoleCodeList(roleCodeList);
        } else {
            partyVO.setRoleCodeList(new ArrayList<String>());
        }

        PartyGroupCacheDO groupCacheDO = partyGroupCache.get(party.getBranchCode());
        if (groupCacheDO != null) {
            partyVO.setBranchName(groupCacheDO.getGroupName());
        }
        List<DepartmentCacheDO> departmentCacheDOS = departmentCache.getAllByPartyGroupCode(groupCacheDO.getCode());
        List<DepartmentCacheDO> collect = departmentCacheDOS.stream().filter(info -> info.getCode().equals(party.getDepartmentCode())).collect(Collectors.toList());
        if (IterUtil.isNotEmpty(collect)){
            partyVO.setDepartmentName(collect.get(0).getName());
        }*/


        return partyVO;
    }


    /**
     * 用户余额统计
     *
     * @param partyBalanceStatisticsDTO
     * @return com.arpa.ntocc.common.common.Page
     * @Date 2019/12/31 16:53
     * @Author wangkf
     */
    @Override
    public Page partyBalanceStatisticsPageList(PartyBalanceStatisticsDTO partyBalanceStatisticsDTO) {
        //排序字段名需要驼峰转数据库下划线类型字段名
        if (StringUtils.isNotEmpty(partyBalanceStatisticsDTO.getSortField())) {
            partyBalanceStatisticsDTO.setSortField(CommonUtil.camel2Underline(partyBalanceStatisticsDTO.getSortField()));
        }

        if (UserUtil.isShipmentOrCompany() || UserUtil.isDriver()) {
            partyBalanceStatisticsDTO.setCode(UserUtil.getCode());
        }

        PartyBalanceStatisticsVo pageListSum = baseMapper.partyBalanceStatisticsPageListSum(partyBalanceStatisticsDTO);
        List<PartyBalanceStatisticsVo> pageList = baseMapper.partyBalanceStatisticsPageList(partyBalanceStatisticsDTO);

        Page page = new Page(partyBalanceStatisticsDTO.getPageNum(), partyBalanceStatisticsDTO.getPageSize());
        page.setRecords(pageList);
        page.setTotal(pageListSum.getTotal());
        page.setSumObject(pageListSum);
        return page;
    }

    /**
     * 查询用户列表
     * 姓名，手机号，模糊搜索
     *
     * @param partySelectDTO
     * @return
     */
    @Override
    public List<PartyCacheDO> selectUser(PartySelectDTO partySelectDTO) {
        List<PartyCacheDO> partyCacheDOList = Lists.newArrayList();
        //如果是司机或者货主，只能查自己
        if (UserUtil.isDriver() || UserUtil.isShipmentOrCompany()) {
            PartyCacheDO partyCacheDO = partyCache.get(UserUtil.getCode());
            partyCacheDOList.add(partyCacheDO);
            return partyCacheDOList;
        }

        List<PartyCacheDO> finalPartyCacheDOList = partyCacheDOList;
        List<String> partyTypeList = partySelectDTO.getPartyTypeList();
        if (!CollectionUtils.isEmpty(partyTypeList)) {
            partyTypeList.forEach(t -> {
                List<PartyCacheDO> temp = partyCache.getListByType(t);
                finalPartyCacheDOList.addAll(temp);
            });
        }
        if (StringUtils.isNotEmpty(partySelectDTO.getPartyType())) {
            List<PartyCacheDO> temp = partyCache.getListByType(partySelectDTO.getPartyType());
            finalPartyCacheDOList.addAll(temp);
        }
        if (!CollectionUtils.isEmpty(finalPartyCacheDOList)) {
            //姓名模糊
            if (StringUtils.isNotBlank(partySelectDTO.getName())) {
                partyCacheDOList = partyCacheDOList.stream().filter(p -> StringUtils.contains(p.getName(), partySelectDTO.getName())).collect(Collectors.toList());
            }
            //手机号模糊
            if (StringUtils.isNotBlank(partySelectDTO.getPhone())) {
                partyCacheDOList = partyCacheDOList.stream().filter(p -> StringUtils.contains(p.getPhone(), partySelectDTO.getPhone())).collect(Collectors.toList());
            }
            //姓名或手机号模糊
            if (StringUtils.isNotBlank(partySelectDTO.getNameOrPhone())) {
                partyCacheDOList = partyCacheDOList.stream().filter(p ->
                        StringUtils.contains(p.getName(), partySelectDTO.getNameOrPhone()) || StringUtils.contains(p.getPhone(), partySelectDTO.getNameOrPhone())
                ).collect(Collectors.toList());
            }
        }
        //限制总数
        if (!CollectionUtils.isEmpty(partyCacheDOList) && partyCacheDOList.size() > partySelectDTO.getMaxSize()) {
            partyCacheDOList = partyCacheDOList.subList(0, partySelectDTO.getMaxSize());
        }
        return partyCacheDOList;
    }



    /**
     * 添加员工信息,不创建登录账号和角色信息
     *
     * @param entity
     * @return
     * @author leo
     */
    @Override
    public boolean saveStaff(PartyDTO entity) {
        if (!ValidateUtil.phone(entity.getPhone())) {
            throw new ServiceException(VALIDATE_PHONE);
        }
        //根据手机号检查用户是否存在
        List<Party> phone = this.list(new QueryWrapper<Party>().lambda().eq(Party::getCode, entity.getPhone().trim())
                .eq(Party::getPartyType,PartyTypeEnum.STAFF.getValue()));
        if (CollectionUtil.isNotEmpty(phone)) {
            throw new ServiceException("手机号已存在");
        }
        //检验员工工号及长度
        validateEmployeeNumber(entity.getEmployeeNumber(),"add");
        if (StringUtils.isBlank(entity.getCode())) {
            entity.setCode(IdUtil.simpleUUID());
        }
        if (StringUtils.isBlank(entity.getCreatedBy())) {
            entity.setCreatedBy(UserUtil.getCode());
        }
        entity.setStatus(0);
        if (StringUtils.isBlank(entity.getBranchCode())) {
            entity.setBranchCode(UserUtil.getBranchCode());
        }

        Party party = new Party();
        BeanUtil.copyProperties(entity, party);
        return super.save(party);
    }

    /**
     * 校验员工工号
     *
     * @param employeeNumber
     * @return
     */
    private void validateEmployeeNumber(String employeeNumber,String operation) {
        if (StringUtils.isEmpty(employeeNumber)) {
            return;
        }
        //验证长度
        if (employeeNumber.getBytes().length > 20) {
            throw new ServiceException("工号不能超过20个字符");
        }

        if ("add".equals(operation)) {
            //验证员工工号是否存在
            int employeeNumberSize = this.baseMapper.selectCount(new LambdaQueryWrapper<Party>().eq(Party::getEmployeeNumber, employeeNumber));
            if (employeeNumberSize > 0) {
                throw new ServiceException("工号" + employeeNumber + "已经存在，请确认");
            }
        }

    }
    /**
     * 根据code更新员工信息
     *
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateStaffByCode(PartyDTO entity) {
        Party party = new Party();
        BeanUtil.copyProperties(entity, party);
        if (StringUtils.isBlank(entity.getModifiedBy())) {
            entity.setModifiedBy(UserUtil.getCode());
        }
        Party dbParty = baseMapper.selectOne(new QueryWrapper<Party>().lambda().eq(Party::getCode, entity.getCode()));
        if (dbParty == null) {
            throw new ServiceException("没有查询到要修改的用户信息");
        }
        List<Party> phone = this.list(new QueryWrapper<Party>().lambda().eq(Party::getCode, entity.getPhone().trim())
                .eq(Party::getPartyType,PartyTypeEnum.STAFF.getValue())
                .ne(Party::getCode, entity.getCode()))
                .stream().collect(Collectors.toList());
        if (phone.size() > 0) {
            throw new ServiceException("该手机号已存在，请重新输入！");
        }
        //校验员工工号及长度
        validateEmployeeNumber(entity.getEmployeeNumber(),"update");
        int num = baseMapper.update(party, new QueryWrapper<Party>().lambda().eq(Party::getCode, entity.getCode()));
        return num;
    }

    /**
     * 查询所有没有登录账号的员工列表
     *
     * @param partyDTO
     * @return
     */
    @Override
    public List<PartyVO> findNotHaveUserLoginStaffs(PartyDTO partyDTO) {
        //排序字段名需要驼峰转数据库下划线类型字段名
        if (StringUtils.isNotEmpty(partyDTO.getSortField())) {
            partyDTO.setSortField(CommonUtil.camel2Underline(partyDTO.getSortField()));
        }
        List<PartyVO> partyVOList = baseMapper.findNotHaveUserLoginStaffs(partyDTO);

        return partyVOList;
    }







}
